from ctypes import c_wchar_p
from functools import reduce
from multiprocessing import Array
from urllib.parse import quote

from flask import request, Response, Blueprint
from gevent.pool import Pool

from api.book import get_chapter_by_the_one_source
from api.slider import get_chapter_by_source_id, get_book_chapter_content, encode_chapter_link
from exts import get_redis, set_redis

download_file = Blueprint('download_file', __name__)


def get_book(chapter_obj, index, result, max_time=10):
    link = chapter_obj.get('link', '')
    link = encode_chapter_link(link)
    redis_key = '/book/content?link={}'.format(link)
    content = get_redis(redis_key)
    print(redis_key)
    if content is None:
        content = {
            'ok': False
        }
        temp_time = 0  # 尝试次数
        while content['ok'] is False:
            try:
                content = get_book_chapter_content(link)
            except BaseException as e:
                print(e)
                content = {
                    'ok': False
                }
            temp_time += 1
            if temp_time > max_time:
                break
            set_redis(redis_key, content)
    chapter_title = chapter_obj.get('title', '')
    chapter = content.get('chapter', {})
    book_content = chapter.get('body', '')
    result[index] = chapter_title + "\n\n" + book_content + "\n\n"


def get_str_array_by_init(arr_len=0, init_str=''):
    temp_arr = Array(c_wchar_p, arr_len, lock=False)
    for i in range(arr_len):
        temp_arr[i] = init_str
    return temp_arr


pool = Pool(1000)


def gen_book(chapters, book_name):
    chapters_len = len(chapters)
    temp = 0
    sockets_length = 150
    while temp < chapters_len:
        temp_len = temp
        temp_chapters = chapters[temp_len: temp_len + sockets_length]
        print(temp_len)
        temp_chapters_len = len(temp_chapters)
        redis_key = "{}_{}-{}".format(book_name, temp_len, temp_len + temp_chapters_len)
        book_content = get_redis(redis_key)
        if book_content is None:
            result = ['' for i in range(temp_chapters_len)]
            for chapter_index, chapter_obj in enumerate(temp_chapters):
                pool.apply_async(get_book, args=(chapter_obj, chapter_index, result))

            pool.join()

            book_content = reduce(lambda x, y: x + y, result)
            set_redis(redis_key, book_content)
        temp += sockets_length
        yield bytes(book_content, encoding='utf-8')


@download_file.route('/download')
def download_book():
    book_id = request.args.get('bookId', '')
    source_id = request.args.get('sourceId', '')
    if source_id:
        book_chapter = get_chapter_by_source_id(source_id)
    else:
        book_chapter = get_chapter_by_the_one_source(book_id)
    if book_chapter:
        chapters = book_chapter.get('chapters', [])
        book_name = book_chapter.get('bookName', '1') + '.txt'
        # make_response()
        filename = quote(book_name, encoding='utf-8')
        filename = filename.replace("+", "%20")
        download_headers = {
            "Content-type": "application/octet-stream",
            "Content-Disposition": "attachment; filename=\"{}\"; filename*=utf-8''{}".format(filename, filename),
            "Cache-Control": "no-cache, no-store, must-revalidate",
            "Pragma": "no-cache",
            "Expires": "0",
            "Connection": "Keep-alive",
            "Keep-Alive": "timeout=180"
        }
        download_mimetype = "application/octet-stream"
        return Response(gen_book(chapters=chapters, book_name=book_name), mimetype=download_mimetype,
                        headers=download_headers,
                        direct_passthrough=True)
